package com.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.commonutils.results;
import com.entity.dto.CoursesRelationDto;
import com.entity.neo4j.*;
import com.entity.pojo.*;
import com.listener.CourseExcelListener;
import com.mapper.*;
import com.service.*;
import com.utils.InitData;
import com.utils.NodeRelation;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author chenmo
 * @since 2022-04-02
 */
@Service
public class CoursesServiceImpl extends ServiceImpl<CoursesMapper, Courses> implements CoursesService {
    @Resource
    private CategoriesService categoriesService;

    @Resource
    private ConceptService conceptService;

    @Resource
    private ResourcesService resourcesService;

    @Resource
    private CoursesRelationService coursesRelationService;

    @Resource
    private CategoriesRelationService categoriesRelationService;

    @Resource
    private ConceptRelationService conceptRelationService;

    @Resource
    private CourseNeoRepository courseNeoRepository;

    @Resource
    private CategoryNeoRepository categoryNeoRepository;

    @Resource
    private ConceptNeoRepository conceptNeoRepository;

    @Resource
    private ResourceNeoRepository resourceNeoRepository;

    @Transactional
    @Override
    public boolean updateCoursesInfo(Courses course) {
        // 如果更新的了课程名称，则需要更新目录表中的课程名称
        Courses oldCourses = baseMapper.selectById(course.getCourseId());
        boolean updateFlag = true;
        boolean saveFlag = false;
        if (!oldCourses.getCourseName().equals(course.getCourseName())) {
            // 说明更新了课程名称，需要更新目录表中的课程名称
            Integer courseId = course.getCourseId();
            List<Categories> categories = categoriesService.list(new QueryWrapper<Categories>().eq("courseId", courseId));
            if (!categories.isEmpty()) {
                categories.forEach(item -> item.setCourseName(course.getCourseName()));
                updateFlag = categoriesService.updateBatchById(categories);
            }
        }
        if (baseMapper.updateById(course) > 0) {
            saveFlag = true;
        }
        return updateFlag & saveFlag;
    }

    // 从Excel中导入课程信息
    @Override
    public void importCourseInfo(MultipartFile courseFile, CoursesService coursesService, InitData initData) {
        try {
            // 文件输入流
            InputStream courseFileInputStream = courseFile.getInputStream();
            EasyExcel.read(courseFileInputStream, Courses.class, new CourseExcelListener(coursesService, initData))
                    .sheet().doRead();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 查询所有课程信息（不分页）
    @Override
    public List<Courses> getAllCourse(Integer courseId) {
        return baseMapper.selectList(null);
    }

    // 以下为Neo4j部分

    /**
     * 测试关系添加案例
     */
    public void testRelation() {
        CourseNode courseNode1 = new CourseNode().setCourseName("c语言程序设计");
        List<CourseNeoRelation> courseNeoRelations = new ArrayList<>();
        CourseNode courseNode2 = courseNeoRepository.findById(348L).orElse(new CourseNode().setCourseName("空白节点"));
        CourseNode courseNode3 = courseNeoRepository.findById(394L).orElse(new CourseNode().setCourseName("空白节点"));
        courseNeoRelations.add(new CourseNeoRelation().setCourseNode(courseNode2).setRelation("全关联"));
        courseNeoRelations.add(new CourseNeoRelation().setCourseNode(courseNode3).setRelation("半关联"));
        courseNode1.setCourseNodeList(courseNeoRelations);
        courseNeoRepository.save(courseNode1);

    }

    @Override
    public results addCourseNode(String newCourseName) {
        // 已存在的节点不能添加
//        List<String> courseNameList = baseMapper.selectList(null).stream().map(Courses::getCourseName).collect(Collectors.toList());
//        if (courseNameList.contains(newCourseName)) {
//            return results.error("该课程节点已存在，请误重复添加");
//        }
        CourseNode courseNode = new CourseNode().setCourseName(newCourseName);
        courseNeoRepository.save(courseNode);
        return results.ok();
    }

    // 根据课程名称查询课程节点
    @Override
    public List<CourseNode> getCoursesNodeByCourseName(String name) {
        return courseNeoRepository.getCoursesNodeByCourseName(name);
    }

    // 根据关系名称查询课程节点
    @Override
    public List<CourseNode> getCoursesNodeByRelation(String relationName) {
        return courseNeoRepository.getCoursesNodeByCourseName(relationName);
    }

    // todo 知识点、资源节点相关待完善
    // 将MySQL数据库中的课程信息转换成Neo4j中的节点信息
    @Override
    public void transformCourseToCourseNode() {
        courseNeoRepository.deleteAll();
        categoryNeoRepository.deleteAll();
        conceptNeoRepository.deleteAll();
        System.out.println("数据库清除完毕");
        // 查询出所有的课程信息
        List<Courses> coursesList = baseMapper.selectList(null);
        // 用作节点缓冲
        final int threshold = 50;
        List<CourseNode> courseNodeList = new LinkedList<>();
        // 遍历课程信息，生成课程节点与其关联的目录信息
        coursesList.forEach(course -> {
            // 查询当前遍历课程的目录信息
            List<Categories> categoriesList = categoriesService.list(new QueryWrapper<Categories>().eq("courseId", course.getCourseId()));
            List<CategoryNode> categoryNodeList = new ArrayList<>();
            // 将对应目录信息加入到当前课程节点中
            categoriesList.forEach(categories -> {
                CategoryNode categoryNode = new CategoryNode();
                BeanUtils.copyProperties(categories, categoryNode);
                categoryNodeList.add(categoryNode);
            });
            CourseNode courseNode = new CourseNode();
            // 将课程信息转换成课程节点
            BeanUtils.copyProperties(course, courseNode);
            courseNode.setCategoryNodeList(categoryNodeList);
            courseNodeList.add(courseNode);
            if (courseNodeList.size() > threshold) {
                courseNeoRepository.saveAll(courseNodeList);
                // 添加后清除缓存
                courseNodeList.clear();
            }
        });
        // 添加剩下的节点
        courseNeoRepository.saveAll(courseNodeList);
        // 添加后清除缓存
        courseNodeList.clear();
        System.out.println("已新增" + coursesList.size() + "个节点，转换成功");
    }

    /**
     * 建立 起始课程 -> 结束课程 的关系
     *
     * @param from     起始课程名称
     * @param relation 关系名称（必须为四种关联等级）
     * @param to       结束课程名称
     */
    @Override
    public results createCourseRelation(String from, String relation, String to) {
        if (!relation.isEmpty() && (relation.equals("全关联") || relation.equals("半关联") || relation.equals("强关联") || relation.equals("弱关联"))) {
            courseNeoRepository.createCourseRelation(from, relation, to);
            return results.ok();
        }
        return results.error("节点信息错误，添加关系失败");
    }

    // 为所有的课程节点建立关系
    @Override
    public void createAllCourseRelation() {
        List<CoursesRelationDto> allCourseRelation = baseMapper.getAllCourseRelation();
        allCourseRelation.forEach(coursesRelationDto -> {
            coursesRelationDto.setRelationName(NodeRelation.relationName(coursesRelationDto.getRelationLevel()));
            courseNeoRepository.createCourseRelation(coursesRelationDto.getCourseName(),
                    coursesRelationDto.getRelationName(),
                    coursesRelationDto.getNextCourseName());
        });
    }

    @Override
    public results getAllNeo4jNode() {
        // 1. 获取所有节点（课程、目录、知识点、资源）
//        List<GeneralNode> generalNodeList = new LinkedList<>();
//        // 1.1 获取所有课程节点
//        List<CourseNode> courseNodeList = courseNeoRepository.findAll();
//        courseNodeList.forEach(node -> {
//            GeneralNode generalNode = new GeneralNode();
//            generalNode.setName(node.getCourseName());
//            generalNode.setType("课程");
//            generalNode.setCode(node.getCourseCode());
//            BeanUtils.copyProperties(node, generalNode);
//            generalNodeList.add(generalNode);
//        });
//        // 1.2 获取所有目录节点
//        List<CategoryNode> categoryNodeList = categoryNeoRepository.findAll();
//        categoryNodeList.forEach(node -> {
//            GeneralNode generalNode = new GeneralNode();
//            generalNode.setName(node.getCategoryName());
//            generalNode.setType("目录");
//            generalNode.setCode(node.getCategoryCode());
//            BeanUtils.copyProperties(node, generalNode);
//            generalNodeList.add(generalNode);
//        });
//        // 1.3 获取所有知识点节点
//        List<ConceptNode> conceptNodeList = conceptNeoRepository.findAll();
//        conceptNodeList.forEach(node -> {
//            GeneralNode generalNode = new GeneralNode();
//            generalNode.setName(node.getConceptName());
//            generalNode.setType("知识点");
//            generalNode.setCode(node.getConceptCode());
//            BeanUtils.copyProperties(node, generalNode);
//            generalNodeList.add(generalNode);
//        });
//        // 1.4 获取所有资源节点
//
//        // 2. 获取所有节点之间的关系
//        List<GeneralRelation> generalNodeRelationList = new LinkedList<>();
//        // 2.1 获取所有课程节点的关系
//        List<CoursesRelation> coursesRelationList = coursesRelationService.list();
//        coursesRelationList.forEach(coursesRelation -> {
//            GeneralRelation generalRelation = new GeneralRelation();
//            generalRelation.setSource(coursesRelation.getCourseId().toString());
//            generalRelation.setTarget(coursesRelation.getNextCourseId().toString());
//            generalRelation.setName(NodeRelation.relationName(coursesRelation.getRelationLevel()));
//            generalNodeRelationList.add(generalRelation);
//        });
//        // 2.2 获取所有目录节点的关系
//        List<CategoriesRelation> categoriesRelationList = categoriesRelationService.list();
//        categoriesRelationList.forEach(categoriesRelation -> {
//            GeneralRelation generalRelation = new GeneralRelation();
//            generalRelation.setSource(categoriesRelation.getCategoryId().toString());
//            generalRelation.setTarget(categoriesRelation.getNextCategoryId().toString());
//            generalRelation.setName(NodeRelation.relationName(categoriesRelation.getRelationLevel()));
//            generalNodeRelationList.add(generalRelation);
//        });
//        // 2.3 获取所有知识点节点的关系
//        List<ConceptRelation> conceptRelationList = conceptRelationService.list();
//        conceptRelationList.forEach(conceptRelation -> {
//            GeneralRelation generalRelation = new GeneralRelation();
//            generalRelation.setSource(((conceptRelation.getConceptId().toString())));
//            generalRelation.setTarget((conceptRelation.getNextConceptId().toString()));
//            generalRelation.setName(NodeRelation.relationName(conceptRelation.getRelationLevel()));
//            generalNodeRelationList.add(generalRelation);
//        });
//        // 2.4 获取所有资源节点的关系
//
//        return results.ok().data("nodes", generalNodeList).data("links", generalNodeRelationList);
        return results.ok();
    }

    // 获取所有课程节点
    public void getAllCourseNodeAndRelation(List<GeneralNode> generalNodeList, List<GeneralRelation> generalNodeRelationList) {
        // 1 获取所有课程节点
        List<Courses> coursesList = baseMapper.selectList(null);
        List<CoursesRelation> coursesRelationList = coursesRelationService.list();
        coursesList.forEach(node -> {
            GeneralNode generalNode = new GeneralNode();
            generalNode.setId(node.getCourseId().toString());
            generalNode.setName(node.getCourseName());
            generalNode.setType("课程");
            generalNode.setCode(node.getCourseCode());
            BeanUtils.copyProperties(node, generalNode);
            generalNodeList.add(generalNode);
        });
        // 2 获取所有课程节点的关系
        coursesRelationList.forEach(relation -> {
            GeneralRelation generalRelation = new GeneralRelation();
            generalRelation.setSource(relation.getCourseId().toString());
            generalRelation.setTarget(relation.getNextCourseId().toString());
            generalRelation.setName(NodeRelation.relationName(relation.getRelationLevel()));
            generalNodeRelationList.add(generalRelation);
        });
    }

    // 获取所有目录节点
    public void getAllCategoryNodeAndRelation(List<GeneralNode> generalNodeList, List<GeneralRelation> generalNodeRelationList) {
        // 1 获取所有目录节点
        List<Categories> categoriesList = categoriesService.list();
        categoriesList.forEach(node -> {
            GeneralNode generalNode = new GeneralNode();
            generalNode.setId(node.getCategoryId().toString());
            generalNode.setName(node.getCategoryName());
            generalNode.setType("目录");
            generalNode.setCode(node.getCategoryCode());
            BeanUtils.copyProperties(node, generalNode);
            generalNodeList.add(generalNode);
            // 1.2目录对应的课程
            GeneralRelation generalRelation = new GeneralRelation();
            generalRelation.setSource(node.getCourseId().toString());
            generalRelation.setTarget(node.getCategoryId().toString());
            generalRelation.setName("目录");
            generalNodeRelationList.add(generalRelation);
        });
        // 2 获取所有目录节点的关系
        List<CategoriesRelation> categoriesRelationList = categoriesRelationService.list();
        categoriesRelationList.forEach(relation -> {
            GeneralRelation generalRelation = new GeneralRelation();
            generalRelation.setSource(relation.getCategoryId().toString());
            generalRelation.setTarget(relation.getNextCategoryId().toString());
            generalRelation.setName(NodeRelation.relationName(relation.getRelationLevel()));
            generalNodeRelationList.add(generalRelation);
        });
    }

    // 获取所有知识点节点
    public void getAllConceptNodeAndRelation(List<GeneralNode> generalNodeList, List<GeneralRelation> generalNodeRelationList) {
        List<Concept> conceptList = conceptService.list();
        conceptList.forEach(node -> {
            GeneralNode generalNode = new GeneralNode();
            generalNode.setId(node.getConceptId().toString());
            generalNode.setName(node.getConceptName());
            generalNode.setType("知识点");
            generalNode.setCode(node.getConceptCode());
            BeanUtils.copyProperties(node, generalNode);
            generalNodeList.add(generalNode);
            // 1.2该目录下的知识点
            GeneralRelation generalRelation = new GeneralRelation();
            generalRelation.setSource(node.getCategoryId().toString());
            generalRelation.setTarget(node.getConceptId().toString());
            generalRelation.setName("知识点");
            generalNodeRelationList.add(generalRelation);
        });
        // 2 获取所有知识点节点的关系
        List<ConceptRelation> conceptRelationList = conceptRelationService.list();
        conceptRelationList.forEach(relation -> {
            GeneralRelation generalRelation = new GeneralRelation();
            generalRelation.setSource(((relation.getConceptId().toString())));
            generalRelation.setTarget((relation.getNextConceptId().toString()));
            generalRelation.setName(NodeRelation.relationName(relation.getRelationLevel()));
            generalNodeRelationList.add(generalRelation);
        });
    }

    // 获取所有资源节点
    public void getAllResourceNodeAndRelation(List<GeneralNode> generalNodeList, List<GeneralRelation> generalNodeRelationList) {
        List<Resources> resourceList = resourcesService.list();
        resourceList.forEach(node -> {
            GeneralNode generalNode = new GeneralNode();
            generalNode.setId(node.getResourceId().toString());
            generalNode.setName(node.getResourceContent());
            generalNode.setType("资源");
            generalNode.setCode(node.getResourceCode());
            BeanUtils.copyProperties(node, generalNode);
            generalNodeList.add(generalNode);
            // 1.2该目录下的知识点
            GeneralRelation generalRelation = new GeneralRelation();
            generalRelation.setSource(node.getConceptId().toString());
            generalRelation.setTarget(node.getResourceId().toString());
            generalRelation.setName("知识点");
            generalNodeRelationList.add(generalRelation);
        });
        // 2 获取所有知识点节点的关系

    }

    @Override
    public results getAllNodeAndRelation() {
        // 1. 获取所有节点（课程、目录、知识点、资源）
        List<GeneralNode> generalNodeList = new LinkedList<>();
        List<GeneralRelation> generalNodeRelationList = new LinkedList<>();
        // 1.1 获取所有课程节点与其关系
        getAllCourseNodeAndRelation(generalNodeList, generalNodeRelationList);
        // 1.2 获取所有目录节点与其关系
        getAllCategoryNodeAndRelation(generalNodeList, generalNodeRelationList);
        // 1.3 获取所有知识点节点与其关系
        getAllConceptNodeAndRelation(generalNodeList, generalNodeRelationList);
        //TODO 1.4 获取所有资源节点与其关系

        return results.ok().data("nodes", generalNodeList).data("links", generalNodeRelationList);
    }
}
